package cn.sangedon.review.analysis.service.impl;

import cn.sangedon.review.analysis.domain.StrategyResultQuery;
import cn.sangedon.review.analysis.mapper.StockStrategyResultMapper;
import cn.sangedon.review.analysis.service.StockStrategyResultService;
import cn.sangedon.review.analysis.stastics.specific.StrategyVerifyStastics;
import cn.sangedon.review.analysis.strategy.specific.FallShrinkRedStrategy;
import cn.sangedon.review.analysis.strategy.specific.RiseShrinkRedStrategy;
import cn.sangedon.review.common.constant.TypeConstant;
import cn.sangedon.review.common.domain.analysis.StockStrategy;
import cn.sangedon.review.common.domain.analysis.StockStrategyResult;
import cn.sangedon.review.common.domain.bean.TradeDateList;
import cn.sangedon.review.common.domain.data.StockDayInfo;
import cn.sangedon.review.common.domain.data.TradingDate;
import cn.sangedon.review.common.service.data.StockDayInfoService;
import cn.sangedon.review.common.service.data.TradingDateService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

/**
 * @author dongliangqiong
 * @description 针对表【tb_stock_strategy_result】的数据库操作Service实现
 * @createDate 2022-08-26 18:00:56
 */
@Service
public class StockStrategyResultServiceImpl extends ServiceImpl<StockStrategyResultMapper, StockStrategyResult> implements
    StockStrategyResultService {
    @Autowired
    private StrategyVerifyStastics strategyVerifyStastics;

    @Autowired
    private FallShrinkRedStrategy fallShrinkRedStrategy;

    @Autowired
    private RiseShrinkRedStrategy riseShrinkRedStrategy;

    @DubboReference
    private TradingDateService tradingDateService;

    @DubboReference
    private StockDayInfoService stockDayInfoService;

    @Override
    public List<StockStrategyResult> getFiveHalfVolResult(StockStrategy stockStrategy) {
        return this.baseMapper.getFiveHalfVolResult(stockStrategy);
    }

    @Override
    public List<StockStrategyResult> getTenAverageVolResult(StockStrategy stockStrategy) {
        return this.baseMapper.getTenAveragefVolResult(stockStrategy);
    }

    @Override
    public void verify() {
        this.baseMapper.updateTodayChangeRateOfYesterdayResult();
    }

    @Override
    public List<StockStrategyResult> getStrategyResult(StrategyResultQuery strategyResultQuery) {
        QueryWrapper<StockStrategyResult> query = new QueryWrapper<>();
        if (strategyResultQuery.unconditional()) {
            query.ge("trading_date", "");
            return this.list(query);
        }

        if (strategyResultQuery.getStrategyId() != null) {
            query.eq("strategy_id", strategyResultQuery.getStrategyId());
        }
        if (StringUtils.hasText(strategyResultQuery.getStartTime())) {
            query.ge("trading_date", strategyResultQuery.getStartTime());
        }
        if (StringUtils.hasText(strategyResultQuery.getEndTime())) {
            query.le("trading_date", strategyResultQuery.getEndTime());
        }

        return this.list(query);
    }

    @Override
    public List<StockStrategyResult> getLatestResult() {
        return this.baseMapper.getLatestResult();
    }

    @Override
    public Long countNeedVerifyResult() {
        return this.baseMapper.countNeedVerifyResult();
    }

    @Override
    public void stockStrategyResultService() {
        strategyVerifyStastics.stastic();
    }

    @Override
    public List<StockStrategyResult> listFallShrinkResult(String tradeDate) {
        return this.baseMapper.listFallShrinkResult(tradeDate);
    }

    @Override
    public void verifyHistoryStrategyResult(String tradeDate) {
        List<StockStrategyResult> strategyResults = this.list();
        Map<String, List<StockStrategyResult>> listMap = strategyResults.stream().filter(e -> e.getTradingDate().equals(tradeDate)).collect(
            Collectors.groupingBy(StockStrategyResult::getTradingDate));

        for (Entry<String, List<StockStrategyResult>> entry : listMap.entrySet()) {
            strategyVerifyStastics.verifyStragegyResult(entry.getValue());
        }
    }

    @Override
    public void executeFallShrinkRedResult(String tradeDate) {
        fallShrinkRedStrategy.execute(tradeDate);
    }

    @Override
    public void executeRiseShrinkRedResult(String tradeDate) {
        riseShrinkRedStrategy.execute(tradeDate);
    }

    @Override
    public void verifyStrategyResult(Long strategyId, String tradeDate) {
        QueryWrapper<StockStrategyResult> query = new QueryWrapper<>();
        query.eq("strategy_id", strategyId);
        query.eq("trading_date", tradeDate);

        List<StockStrategyResult> strategyResults = this.list(query);
        if (CollectionUtils.isEmpty(strategyResults)) {
            return;
        }
        strategyVerifyStastics.verifyStragegyResult(strategyResults);
    }

    @Override
    public Map<String, Object> verifyStrategy() {
        List<StockStrategyResult> list = this.list();
        Map<String, List<StockStrategyResult>> dateGroup = list.stream()
                                                               .collect(Collectors.groupingBy(StockStrategyResult::getTradingDate));
        for (String tradeDate : dateGroup.keySet()) {
            List<StockStrategyResult> stockStrategyResults = dateGroup.get(tradeDate);
            TradeDateList tradeDateList = tradingDateService.postTradingDay(tradeDate, 3);

            // 计算第二个交易日
            TradingDate tomorrow = tradeDateList.behind(tradeDateList.current().getTradingDate());
            List<StockDayInfo> stockDayInfos = stockDayInfoService.getStockDayInfos(tomorrow.getTradingDate(), TypeConstant.EQ);
            if (CollectionUtils.isEmpty(stockDayInfos)) {
                continue;
            }
            Map<String, StockDayInfo> codeGroup = stockDayInfos.stream()
                                                               .collect(Collectors.toMap(StockDayInfo::getCode, Function.identity()));
            stockStrategyResults.forEach(e -> {
                StockDayInfo stockDayInfo = codeGroup.get(e.getStockCode());
                e.setPeekChangeRate2(calulateChangeRate(stockDayInfo.getPeakPrice(), stockDayInfo.getLastClosePrice()));
                e.setChangeRate2(stockDayInfo.getChangeRate().toString());
                e.setPeekChangeRate2(calulateChangeRate(stockDayInfo.getBottomPrice(), stockDayInfo.getLastClosePrice()));
            });

            // 计算第三个交易日
            TradingDate behind = tradeDateList.behind(tomorrow.getTradingDate());
            List<StockDayInfo> behindStockDayInfos = stockDayInfoService.getStockDayInfos(behind.getTradingDate(), TypeConstant.EQ);
            if (CollectionUtils.isEmpty(behindStockDayInfos)) {
                continue;
            }
            Map<String, StockDayInfo> behindCodeGroup = behindStockDayInfos.stream().collect(
                Collectors.toMap(StockDayInfo::getCode, Function.identity()));
            stockStrategyResults.forEach(e -> {
                StockDayInfo stockDayInfo = behindCodeGroup.get(e.getStockCode());
                e.setPeekChangeRate3(calulateChangeRate(stockDayInfo.getPeakPrice(), stockDayInfo.getLastClosePrice()));
                e.setChangeRate3(stockDayInfo.getChangeRate().toString());
                e.setBottomChangeRate3(calulateChangeRate(stockDayInfo.getBottomPrice(), stockDayInfo.getLastClosePrice()));
            });
        }

        this.saveOrUpdateBatch(list);
        return null;
    }

    private String calulateChangeRate(BigDecimal bottomPrice, BigDecimal openingPrice) {
        double value = bottomPrice.subtract(openingPrice).divide(openingPrice, 4, RoundingMode.HALF_UP).doubleValue() * 100;
        return String.valueOf(value);
    }
}




